﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using DepSoft.Gui.iExporter.Properties;
using DepSoft.Helpers.Extensions;
using DepSoft.Helpers.iTunes;
using DepSoft.Helpers.iTunes.Elements;
using Microsoft.WindowsAPICodePack.Taskbar;
using PH.DataTree;

namespace DepSoft.Gui.iExporter
{
    public partial class FrmMain : Form
    {
        #region Private members
        iTunesLib               _iTunesLibrary              = new iTunesLib();
        List<iTunesPlaylist>    _iTunesPlayListToExport     = new List<iTunesPlaylist>();
        List<string>            _iTunesAlbumArtistsToExport = new List<string>();
        List<string>            _iTunesAlbumArtists         = new List<string>();
        TaskbarManager          _windowsTaskbar             = TaskbarManager.Instance;
        Boolean                 _iExporterLoading;
        #endregion

        #region Constructor
        public FrmMain()
        {
            _iExporterLoading = true;
            InitializeComponent();
            InitializeBackGroundWorker();
            InitializeVariables();
            InitializeControls();
        }
        #endregion

        #region Private methods
        #region BackgroundWorker methods
        private void InitializeBackGroundWorker()
        {
            this.backgroundWorker_Export.WorkerReportsProgress = true;
            this.backgroundWorker_Export.WorkerSupportsCancellation = true;
            this.backgroundWorker_Export.DoWork += new DoWorkEventHandler(backgroundWorker_Export_DoWork);
            this.backgroundWorker_Export.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_Export_RunWorkerCompleted);
            this.backgroundWorker_Export.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_Export_ProgressChanged);
        }

        private void backgroundWorker_Export_DoWork(object sender, DoWorkEventArgs e)
        {
            switch ((string)e.Argument)
            {
                case "tabiTunesPlaylists":
                    iTunesPlaylistExportConfiguration playListExportConfiguration = new iTunesPlaylistExportConfiguration()
                    {
                        //Check InvokeRequired needed because the ComboBoxes are DataBound, this will generate a Cross Threading exception with BackGroundWorker thread
                        PlaylistMode = InvokeRequired ? (PlaylistModeEnum)this.cboPlaylistMode.Invoke(new Func<PlaylistModeEnum>(delegate
                            {
                                return (PlaylistModeEnum)this.cboPlaylistMode.SelectedItem;
                            }))
                            : (PlaylistModeEnum)this.cboPlaylistMode.SelectedItem,
                        //Check InvokeRequired needed because the ComboBoxes are DataBound, this will generate a Cross Threading exception with BackGroundWorker thread
                        ExportMode = InvokeRequired ? (ExportModeEnum)this.cboTracksMode.Invoke(new Func<ExportModeEnum>(delegate
                            {
                                return (ExportModeEnum)this.cboTracksMode.SelectedItem;
                            }))
                            : (ExportModeEnum)this.cboTracksMode.SelectedItem,
                        PlaylistPathRoot = this.chkPlaylistPathRoot.Checked,
                        iTunesElementList = this._iTunesPlayListToExport,
                        ExportLocation = this.txtExportLocation.Text,
                        CreateSubFolders = this.chkAlbumFolders.Checked,
                        BackgroundWorker = this.backgroundWorker_Export
                    };

                    e.Result = this._iTunesLibrary.ExportPlaylists(playListExportConfiguration);

                    //if (this.chkExportFiles.Checked)
                    //    e.Result = this._iTunesLibrary.ExportPlayLists(this._iTunesPlayListToExport, this.txtExportLocation.Text, this.chkAlbumFolders.Checked, Settings.Default.iExportExportMode, this.backgroundWorker_Export);
                    //else
                    //    e.Result = this._iTunesLibrary.ExportPlayLists(new iTunesPlaylistExportConfiguration()
                    //    {
                    //        PlaylistMode = this.chkExportPlaylist.Checked ? PlaylistModeEnum.Minimal : PlaylistModeEnum.Normal,
                    //        ExportMode = ExportModeEnum.None,
                    //        iTunesElementList = this._iTunesPlayListToExport,
                    //        ExportLocation = this.txtExportLocation.Text
                    //    }
                    //    );

                        //e.Result = this._iTunesLibrary.ExportPlayLists(this._iTunesPlayListToExport, this.txtExportLocation.Text);
                    break;
                case "tabiTunesArtists":
                    //e.Result = this._iTunesLibrary.ExportArtists(this._iTunesAlbumArtistsToExport, this.txtExportLocation.Text, this.chkAlbumFolders.Checked, Settings.Default.iExportExportMode, this.backgroundWorker_Export);

                    List<iTunesTrack> tracksToExport = (from iTunesTrack track in this._iTunesLibrary.iTunesTracks
                                                        where this._iTunesAlbumArtistsToExport.Exists(delegate(string argument)
                                                        {
                                                            return argument.Equals(track.AlbumArtist, StringComparison.OrdinalIgnoreCase);
                                                        })
                                                        select track).Distinct().ToList();

                    iTunesTrackExportConfiguration tracksExportConfiguration = new iTunesTrackExportConfiguration()
                    {
                        //Check InvokeRequired needed because the ComboBoxes are DataBound, this will generate a Cross Threading exception with BackGroundWorker thread
                        PlaylistMode = InvokeRequired ? (PlaylistModeEnum)this.cboPlaylistMode.Invoke(new Func<PlaylistModeEnum>(delegate
                            {
                                return (PlaylistModeEnum)this.cboPlaylistMode.SelectedItem;
                            }))
                            : (PlaylistModeEnum)this.cboPlaylistMode.SelectedItem,
                        //Check InvokeRequired needed because the ComboBoxes are DataBound, this will generate a Cross Threading exception with BackGroundWorker thread
                        ExportMode = InvokeRequired ? (ExportModeEnum)this.cboTracksMode.Invoke(new Func<ExportModeEnum>(delegate
                            {
                                return (ExportModeEnum)this.cboTracksMode.SelectedItem;
                            }))
                            : (ExportModeEnum)this.cboTracksMode.SelectedItem,
                        iTunesElementList = tracksToExport,
                        PlaylistPathRoot = this.chkPlaylistPathRoot.Checked,
                        ExportLocation = this.txtExportLocation.Text,
                        CreateSubFolders = this.chkAlbumFolders.Checked,
                        BackgroundWorker = this.backgroundWorker_Export
                    };

                    e.Result = this._iTunesLibrary.ExportArtists(tracksExportConfiguration);
                    break;
                default:
                    break;
            }
        }

        private void backgroundWorker_Export_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.toolStripStatusLabel.Text = string.Concat("Exporting ", e.UserState as string, "...");
            this.progressBar.Value = e.ProgressPercentage;

            _windowsTaskbar.SetProgressValue(e.ProgressPercentage, 100);
        }

        private void backgroundWorker_Export_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (((bool)e.Result))
                MessageBox.Show("Export completed");
            else
                MessageBox.Show("Export failed");

            this.toolStripStatusLabel.Text = string.Concat(this._iTunesLibrary.iTunesPlayLists.Count().ToString(), " playlists - ", this._iTunesAlbumArtists.Count().ToString(), " album artists - ", this._iTunesLibrary.iTunesTracks.Count().ToString(), " tracks");
            this.progressBar.Value = 1;
            _windowsTaskbar.SetProgressValue(0, 100);
        }
        #endregion

        #region Initialization
        private void InitializeVariables()
        {
            if (string.IsNullOrEmpty(Settings.Default.iTunesLibraryFile))
                this.txtiTunesLibraryFile.Text = _iTunesLibrary.iTunesLibraryFile;
            else
                this.txtiTunesLibraryFile.Text = Settings.Default.iTunesLibraryFile;

            this.txtExportLocation.Text = Settings.Default.iExporterDirectory;
            this.chkAlbumFolders.Checked = Settings.Default.iExportAlbumFolders;

            this.chkPlaylistMode.Checked = Settings.Default.iExportPlaylistMode;
            this.chkTracksMode.Checked = Settings.Default.iExportTrackMode;

            this.chkPlaylistPathRoot.Checked = Settings.Default.iExportPlaylistPathRoot;
        }

        private void InitializeControls()
        {
            this.progressBar.Minimum = 1;
            this.progressBar.Maximum = 100;
            this.progressBar.Value = 1;

            this.cboPlaylistMode.DataSource = Enum.GetValues(typeof(PlaylistModeEnum));
            this.cboTracksMode.DataSource = Enum.GetValues(typeof(ExportModeEnum));

            this.cmdSelect.Enabled = false;
            this.cmdDeselect.Enabled = false;

            this.ChangeModeControls();

            if (!this.chkTracksMode.Checked)
            {
                this.cboTracksMode.SelectedItem = ExportModeEnum.None;
                this.cboTracksMode.Enabled = false;
            }
            else
            {
                this.cboTracksMode.SelectedItem = ExportModeEnum.Normal;
                this.cboTracksMode.Enabled = true;
            }

            if (!this.chkPlaylistMode.Checked)
            {
                this.cboPlaylistMode.SelectedItem = PlaylistModeEnum.None;
                this.cboPlaylistMode.Enabled = false;
            }
            else
            {
                this.cboPlaylistMode.SelectedItem = PlaylistModeEnum.Normal;
                this.cboPlaylistMode.Enabled = true;
            }
        }

        private void ChangeModeControls()
        {
            if (string.IsNullOrEmpty(this.txtExportLocation.Text))
            {
                this.cmdExport.Enabled = false;
                this.cmdiTunesConnect.Enabled = false;
                this.tabiTunesSelection.Enabled = false;
            }
            else
            {
                this.cmdExport.Enabled = this._iTunesPlayListToExport.Count > 0 || this._iTunesAlbumArtistsToExport.Count > 0; //true;
                this.cmdiTunesConnect.Enabled = true;
                this.tabiTunesSelection.Enabled = true;
            }

            if (!_iExporterLoading && !ReferenceEquals(this._iTunesLibrary.iTunesPlayLists, null)
                && !ReferenceEquals(this._iTunesAlbumArtists, null)
                && !ReferenceEquals(this._iTunesAlbumArtistsToExport, null)
                && !ReferenceEquals(this._iTunesPlayListToExport, null))
            {
                this.cmdSelect.Enabled = this._iTunesLibrary.iTunesPlayLists.Count() > 0 || this._iTunesAlbumArtists.Count() > 0;
                this.cmdDeselect.Enabled = this._iTunesAlbumArtistsToExport.Count > 0 || this._iTunesPlayListToExport.Count > 0;
            }
        }        
        #endregion

        private void FrmMain_Load(object sender, EventArgs e)
        {
            _iExporterLoading = false;
        }

        private void cmdiTunesConnect_Click(object sender, EventArgs e)
        {
            _windowsTaskbar.SetProgressState(TaskbarProgressBarState.Normal);

            try
            {
                Cursor = Cursors.WaitCursor;
                this._iTunesLibrary.iTunesLibraryFile = this.txtiTunesLibraryFile.Text;
                this._iTunesLibrary.ParseiTunesLibrary();

                Dictionary<string, DTreeNode<iTunesPlaylist>> playListDictionary = new Dictionary<string, DTreeNode<iTunesPlaylist>>();
                DTreeNode<iTunesPlaylist> playListNode;
                DTreeNode<iTunesPlaylist> tree = new DTreeNode<iTunesPlaylist>();

                foreach (iTunesPlaylist playList in this._iTunesLibrary.iTunesPlayLists)
                {
                    if (ReferenceEquals(playList.Parent, null))
                        playListNode = tree.Nodes.Add(playList);
                    else
                        playListNode = playListDictionary[playList.Parent.PlaylistPersistentID].Nodes.Add(playList);

                    playListDictionary.Add(playList.PlaylistPersistentID, playListNode);
                }

                TreeViewController<iTunesPlaylist> playListTreeController = new TreeViewController<iTunesPlaylist>(this.playListsTreeView, tree, new iTunesPlayListMapper());

                this._iTunesAlbumArtists = (from track in this._iTunesLibrary.iTunesTracks
                                            where !string.IsNullOrEmpty(track.AlbumArtist)
                                            orderby track.AlbumArtist
                                            select track.AlbumArtist.ToLowerInvariant().ToTitleCase()).Distinct().ToList();

                DTreeNode<string> albumArtistListNode = new DTreeNode<string>();
                foreach (string albumArtist in _iTunesAlbumArtists)
                    albumArtistListNode.Nodes.Add(albumArtist);

                TreeViewController<string> albumArtistTreeController = new TreeViewController<string>(this.albumArtistsTreeView, albumArtistListNode);

                this.toolStripStatusLabel.Text = string.Concat(this._iTunesLibrary.iTunesPlayLists.Count().ToString(), " playlists - ", this._iTunesAlbumArtists.Count().ToString(), " album artists - ", this._iTunesLibrary.iTunesTracks.Count().ToString(), " tracks");

                this.cmdSelect.Enabled = this._iTunesLibrary.iTunesPlayLists.Count() > 0 || this._iTunesAlbumArtists.Count() > 0;
            }
            catch (Exception ex)
            {
                if (ex is FileNotFoundException || ex is DirectoryNotFoundException)
                    MessageBox.Show(ex.Message, "iTunes library load", MessageBoxButtons.OK, MessageBoxIcon.Error);
                else
                    throw;
            }
            finally
            {
                Cursor = Cursors.Default;
            }
        }

        private void cmdExport_Click(object sender, EventArgs e)
        {
            bool exportFiles = true;
            //if (this.chkDeleteExportLocationFolder.Checked && this.tabiTunesSelection.SelectedTab.Name.Equals("tabiTunesArtists"))
            //    exportFiles = MessageBox.Show("Beware! Cleaning export location folders when exporting tracks will delete all tracks in the containing folder!" + Environment.NewLine + "Continue?", "Clear export location", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes ? true : false;
            
            if (!this.backgroundWorker_Export.IsBusy && exportFiles)
                this.backgroundWorker_Export.RunWorkerAsync(this.tabiTunesSelection.SelectedTab.Name);
        }

        private void cmdSelectiWatchDirectory_Click(object sender, EventArgs e)
        {
            if (this.folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                Settings.Default.iExporterDirectory = this.folderBrowserDialog.SelectedPath;
                Settings.Default.Save();

                this.txtExportLocation.Text = Settings.Default.iExporterDirectory;
                this.folderBrowserDialog.SelectedPath = Settings.Default.iExporterDirectory;

                this.InitializeControls();
            }
        }

        private void cmdSelectiTunesLibraryFile_Click(object sender, EventArgs e)
        {
            if (this.openFileDialog.ShowDialog() == DialogResult.OK)
            {
                Settings.Default.iTunesLibraryFile = this.openFileDialog.FileName;
                Settings.Default.Save();

                this.txtiTunesLibraryFile.Text = Settings.Default.iTunesLibraryFile;
                this.openFileDialog.InitialDirectory = Path.GetDirectoryName(Settings.Default.iTunesLibraryFile);

                this.InitializeControls();
            }
        }

        private void tabiTunesSelection_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (this.tabiTunesSelection.SelectedTab.Name)
            {
                case "tabiTunesPlaylists":
                    //this.chkExportFiles.Enabled = true;
                    //this.radioSyncMode.Visible = true;
                    //this.chkExportFiles.Visible = true;
                    //this.toolStripStatusLabel.Text = string.Concat("Playlists available - ", this._iTunesLibrary.iTunesPlayLists.Count().ToString());
                    break;
                case "tabiTunesArtists":
                    //this.chkExportFiles.Enabled = false;
                    //this.chkExportFiles.Checked = true;
                    //this.radioSyncMode.Visible = false;
                    //if(this.radioSyncMode.Checked)
                    //    this.radioNormal.Checked = true;
                    //this.chkExportFiles.Visible = false;
                    //this.toolStripStatusLabel.Text = string.Concat("Tracks available - ", this._iTunesLibrary.iTunesTracks.Count().ToString());
                    break;
                default:
                    break;
            }
        }

        private void playListsTreeView_AfterCheck(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Checked)
                this._iTunesPlayListToExport.Add((iTunesPlaylist)e.Node.Tag);
            else
                this._iTunesPlayListToExport.Remove((iTunesPlaylist)e.Node.Tag);

            this.ChangeModeControls();
        }

        private void albumArtistsTreeView_AfterCheck(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Checked)
                this._iTunesAlbumArtistsToExport.Add(e.Node.Text);
            else
                this._iTunesAlbumArtistsToExport.Remove(e.Node.Text);

            this.ChangeModeControls();
        }

        private void chkAlbumFolders_CheckedChanged(object sender, EventArgs e)
        {
            if (!_iExporterLoading)
            {
                Settings.Default.iExportAlbumFolders = this.chkAlbumFolders.Checked;
                Settings.Default.Save();
            }
        }

        private void chkTracksMode_CheckedChanged(object sender, EventArgs e)
        {
            if (!_iExporterLoading)
            {
                if (!this.chkTracksMode.Checked)
                {
                    this.cboTracksMode.SelectedItem = ExportModeEnum.None;
                    this.cboTracksMode.Enabled = false;
                }
                else
                {
                    this.cboTracksMode.SelectedItem = ExportModeEnum.Normal;
                    this.cboTracksMode.Enabled = true;
                }

                Settings.Default.iExportTrackMode = this.chkTracksMode.Checked;
                Settings.Default.Save();
            }
        }

        private void chkPlaylistMode_CheckedChanged(object sender, EventArgs e)
        {
            if (!_iExporterLoading)
            {
                if (!this.chkPlaylistMode.Checked)
                {
                    this.cboPlaylistMode.SelectedItem = PlaylistModeEnum.None;
                    this.cboPlaylistMode.Enabled = false;
                }
                else
                {
                    this.cboPlaylistMode.SelectedItem = PlaylistModeEnum.Normal;
                    this.cboPlaylistMode.Enabled = true;
                }

                Settings.Default.iExportPlaylistMode = this.chkPlaylistMode.Checked;
                Settings.Default.Save();
            }
        }

        private void chkPlaylistPathRoot_CheckedChanged(object sender, EventArgs e)
        {
            if (!_iExporterLoading)
            {
                Settings.Default.iExportPlaylistPathRoot = this.chkPlaylistPathRoot.Checked;
                Settings.Default.Save();
            }
        }

        private void cmdSelect_Click(object sender, EventArgs e)
        {
            switch (this.tabiTunesSelection.SelectedTab.Name)
            {
                case "tabiTunesPlaylists":
                    var iTunesPlaylists = (from TreeNode treeNode in this.playListsTreeView.Nodes.GetItems<TreeNode>(item => item.Nodes)
                                           where treeNode.Checked == false
                                           select treeNode.Checked = true).ToArray();
                    //this.playListsTreeView.Nodes.GetItems<TreeNode>(item => item.Nodes).All(item => item.Checked = true);
                    break;
                case "tabiTunesArtists":
                    var iTunesArtists = (from TreeNode treeNode in this.albumArtistsTreeView.Nodes.GetItems<TreeNode>(item => item.Nodes)
                                         where treeNode.Checked == false
                                         select treeNode.Checked = true).ToArray();
                    //this.albumArtistsTreeView.Nodes.GetItems<TreeNode>(item => item.Nodes).All(item => item.Checked = true);
                    break;
            }
        }

        private void cmdDeselect_Click(object sender, EventArgs e)
        {
            switch (this.tabiTunesSelection.SelectedTab.Name)
            {
                case "tabiTunesPlaylists":
                    var iTunesPlaylists = (from TreeNode treeNode in this.playListsTreeView.Nodes.GetItems<TreeNode>(item => item.Nodes)
                                           where treeNode.Checked == true
                                           select treeNode.Checked = false).ToArray();
                    break;
                case "tabiTunesArtists":
                    var iTunesArtists = (from TreeNode treeNode in this.albumArtistsTreeView.Nodes.GetItems<TreeNode>(item => item.Nodes)
                                         where treeNode.Checked == true
                                         select treeNode.Checked = false).ToArray();
                    break;
            }
        }

        private void paypalPictureBox_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2EX59N6GY6L92&lc=BE&item_name=DepSoft&item_number=iExporter&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted");
        }

        private void paypalPictureBox_MouseEnter(object sender, EventArgs e)
        {
            Cursor = Cursors.Hand;
        }

        private void paypalPictureBox_MouseLeave(object sender, EventArgs e)
        {
            Cursor = Cursors.Default;
        }

        private void picTrackMode_Click(object sender, EventArgs e)
        {
            FrmHelp frmHelp = new FrmHelp();
            frmHelp.ShowDialog();
        }

        private void picTrackMode_MouseHover(object sender, EventArgs e)
        {
            Cursor = Cursors.Hand;
        }

        private void picTrackMode_MouseLeave(object sender, EventArgs e)
        {
            Cursor = Cursors.Default;
        }

        private void picPlaylistMode_MouseClick(object sender, MouseEventArgs e)
        {
            FrmHelp frmHelp = new FrmHelp();
            frmHelp.ShowDialog();
        }

        private void picPlaylistMode_MouseHover(object sender, EventArgs e)
        {
            Cursor = Cursors.Hand;
        }

        private void picPlaylistMode_MouseLeave(object sender, EventArgs e)
        {
            Cursor = Cursors.Default;
        }
        #endregion
    }
}